/***********************************************************
 *                 Design by tanxiao                       *
 ***********************************************************
 *                                                         *
 *                                                         *
 *                                                         *
 *                                                         *
 ***********************************************************
 ***********************************************************
 *    Project : Hacc UVM testbench                         *
 *    File    : ahb_master_driver.sv                       *
 *    Designer: tan xiao                                   *
 *    Date    : Jul 22    CST          2013                *
 *    Descripton : AHB master driver                       *
 ***********************************************************
 ***********************************************************
 *  Revision History :                                     *
    $Log: ahb_if.sv $
    Revision 1.1 2013/07/22             tanxiao 
    initial  import


 ***********************************************************/


`ifndef   AHB_MASTER_DRIVER_SV 
`define   AHB_MASTER_DRIVER_SV 


class ahb_master_driver extends uvm_driver#(ahb_transfer);


  //The virtual interface used drive and view HDL signals
  virtual interface AHB_IF   regAHB_vif    ;

  // Count transfer sent
  int   num_sent    ;

  // Provide implementation of virtual methods such as get_type_name and creat
  `uvm_component_utils(ahb_master_driver)

  //Constructor  - required syntax for UVM automation and utilities
  function new(string name, uvm_component parent);
      super.new(name, parent);
  endfunction :new

  // Additional class methods
  extern virtual  function void build_phase(uvm_phase phase);
  extern virtual  task run_phase(uvm_phase phase);
  extern virtual  task reset_phase(uvm_phase phase);
  extern virtual  protected task get_and_drive();
  extern virtual  protected task reset_signals();
  extern virtual  protected task drive_transfer(ahb_transfer trans);
  extern virtual  function void report();

endclass : ahb_master_driver



// UVM_build_phase
function void ahb_master_driver::build_phase(uvm_phase phase);
     
     super.build_phase(phase) ;
     if(!uvm_config_db#(virtual AHB_IF)::get(this, "", "regAHB_vif", regAHB_vif))
          `uvm_fatal("NOVIF", {"virtual interface must be for:, ",get_full_name(), ".regAHB_vif"})
     
endfunction : build_phase


// UVM run_phase
task ahb_master_driver::reset_phase(uvm_phase phase);
  super.reset_phase(phase);
  regAHB_vif.HADDR   = 'h0             ;
  regAHB_vif.HTRANS  = IDLE            ;
  regAHB_vif.HWDATA  = 'h0             ;
  regAHB_vif.HBURST  = SINGLE          ;
  regAHB_vif.HSIZE   = BYTE            ;
  regAHB_vif.HWRITE  = READ            ;
  regAHB_vif.HSELx   = 'b0            ;
endtask : reset_phase
task ahb_master_driver::run_phase(uvm_phase phase) ;
   fork 
     get_and_drive();
     //reset_signals();
   join
endtask : run_phase


// Gets transfer from sequencer and phase them to the driver
task ahb_master_driver::get_and_drive();
   @(posedge regAHB_vif.HRESETn);
   `uvm_info(get_type_name(), "Reset dropped", UVM_MEDIUM)

   forever begin
     @(posedge regAHB_vif.HCLK iff (regAHB_vif.HREADYOUT === 1 && regAHB_vif.HREADY === 1));
     // Get new item from the sequencer
     seq_item_port.get_next_item(req);

     if(req.direction == READ) begin
         $cast(rsp, req.clone());
         rsp.set_id_info(req);
         drive_transfer(rsp);
     end
     else begin
         drive_transfer(req);
     end

     // Communicate item done to the sequencer
     seq_item_port.item_done();

     if(req.direction == READ) begin
            seq_item_port.put_response(rsp);
     end

   end
endtask : get_and_drive






// Get a transfer and drive it into DUT
task ahb_master_driver::drive_transfer(ahb_transfer trans);
   @(posedge regAHB_vif.HCLK iff(regAHB_vif.HREADYOUT === 1 && regAHB_vif.HREADY === 1));

   regAHB_vif.HSELx   = 1'b1            ;
   regAHB_vif.HTRANS  = NONSEQ          ;
   regAHB_vif.HWRITE  = trans.direction ;
   regAHB_vif.HSIZE   = trans.hsize     ;
   //regAHB_vif.HPROT   = trans.prot      ;
   regAHB_vif.HBURST  = trans.burst     ;
   regAHB_vif.HADDR   = trans.address   ;

   
   if(trans.direction == WRITE ) begin
      //@(posedge regAHB_vif.HCLK iff(regAHB_vif.HREADYOUT === 1 && regAHB_vif.HREADY === 1));
      @(posedge regAHB_vif.HCLK iff(regAHB_vif.HREADYOUT === 1));
      regAHB_vif.HWDATA = trans.data   ;
      regAHB_vif.HTRANS = IDLE    ;

   end
   else if(trans.direction == READ) begin
      @(posedge regAHB_vif.HCLK );
      regAHB_vif.HTRANS = IDLE    ;
      //@(posedge regAHB_vif.HCLK iff(regAHB_vif.HREADYOUT === 1 && regAHB_vif.HREADY === 1));
      @(posedge regAHB_vif.HCLK iff(regAHB_vif.HREADYOUT === 1));
      trans.data = regAHB_vif.HRDATA ;
   end

   regAHB_vif.HSELx = 1'b0 ;

   num_sent++ ;
   `uvm_info(get_type_name(), $psprintf("Item %0d Sent ...", num_sent), UVM_HIGH)

endtask : drive_transfer


// UVM report() phase
function void ahb_master_driver::report();
   `uvm_info(get_type_name(),
     $psprintf("\nReport: AHB master driver sent %0d transfer",
     num_sent), UVM_LOW)
endfunction : report

`endif //AHB_MASTER_DRIVER_SV




// Reset all master signals
task ahb_master_driver::reset_signals();
   forever begin
      @(negedge regAHB_vif.HRESETn);
      `uvm_info(get_type_name(), "Reset observed", UVM_MEDIUM)

       regAHB_vif.HADDR   = 'h0             ;
       regAHB_vif.HTRANS  = IDLE            ;
       regAHB_vif.HWDATA  = 'h0             ;
       regAHB_vif.HBURST  = SINGLE          ;
       regAHB_vif.HSIZE   = BYTE            ;
       regAHB_vif.HWRITE  = READ            ;
       regAHB_vif.HSELx   = 'b0            ;

   end
endtask : reset_signals

